# coding:utf-8
import socket;

class ftpclient:
    
    def __init__(self, host, port=21, username=None, passwd=None):
        self.host = host;
        self.port = port;
        self.username = username;
        self.passwd = passwd;
        self.opreate = None;
        self.translate = None;
        self.Isconnect = False;
    
    def _connect(self, username=None, passwd=None):
        
        if(username):
            self.username = username;
        if(passwd):
            self.passwd = passwd;
        
        if(not self.username):
            return 'username error';
        if(not self.passwd):
            return 'passwd error';
        
        self.opreate = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0);
        serveraddress = (self.host, self.port);
        
        try:
            
            self.opreate.connect(serveraddress);
            
            self.Isconnect = True;
            
        except Exception, e:
            
            self.Isconnect = False;
            
            print e;
            
            pass
        
        return self.Isconnect;
        
        pass
    
    '登錄'
    def login(self, username=None, passwd=None):
        
        self._connect(username, passwd);
        
        if(self.Isconnect):
            
            code, msg = self.opreateReceve();
                        
            command = 'USER %s\r\n' % self.username;
            
            code, msg = self.opreateSend(command);             
            if(code == '331'):
                
                command = 'PASS %s\r\n' % self.passwd;                
                code, msg = self.opreateSend(command);                 
                if(code == '230'):
                    print msg;
                    return True;
                else:
                    print msg
                    return False;
            else:
                print 'username error';
                return False;
        else:
            return False;
        
        pass
    
    '操作socket 接受数据'
    def opreateReceve(self):
        
        try:
            '循环接收消息'
            
            if(self.Isconnect):
                
                recvbuff = self.opreate.recv(1024);
                
                if(not recvbuff):
                    return ('-1', 'error');
                else:
                    spaceindex = recvbuff.find(' ');
                    statecode = recvbuff[0:spaceindex];
                    message = recvbuff[spaceindex:-1].strip();
                    print statecode, message;
                    return (statecode, message);
                
                pass
            
        except Exception, e:
            self.Isconnect = False;
            return ('-2', e);
        
        pass
    
    '发送'
    def opreateSend(self, command):
        
        try:
            if(self.Isconnect):
                
                buf = buffer(command);
                
                self.opreate.sendall(buf);
                
                return self.opreateReceve();
                            
        except Exception , e:
            print e;
            return ('-3', e);
            
        pass
    
    '上传'
    def upload(self, sourcefile, targetfile, flag=True, callback=None):
        
        '首先设置传输模式'
        '在设置PASV'
        try:
            
            '获取服务器上面文件的大小'
            '用来实现断点续传'
            command = 'SIZE %s\r\n' % targetfile;
            code, msg = self.opreateSend(command);
            
            curlen = 0;            
            fileseek = 0;
            
            if(code == '213'):
                fileseek = int(msg);
                curlen = fileseek;
            
            self.SetType(flag);
            
            ip, port = self.SetPASV();            
            transaddress = (ip, port);
            
            trans = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0);            
            trans.connect(transaddress);
            
            localfile = open(sourcefile, 'rb');
            localfile.seek(fileseek);
            
            command = 'STOR %s\r\n' % targetfile;
            code, msg = self.opreateSend(command);
            
            if(code != '150'):
                return msg;
                        
            while(True):
                str_rd = localfile.read(1024);
                if(not str_rd):
                    break;
                else:
                    curlen += 1024;
                    sendBuff = buffer(str_rd);
                    trans.send(sendBuff);
                    try:
                        if(callback):
                            callback(curlen);
                    except Exception, e:
                        print e;
            
            '传输结束'
            localfile.close();
            trans.close();
            
            code, msg = self.opreateReceve();
            
        except Exception, e:
            print e;
        finally:
            if(flag):
                self.SetType(not flag);
            
        pass
    
    '返回ip和端口'
    def SetPASV(self):
        
        command = 'PASV \r\n';
        
        code, msg = self.opreateSend(command);
        
        if(code == '227'):
            indexleft = msg.find('(') + 1;
            indexright = msg.find(')');
            str_v = msg[indexleft:indexright];
            dict_v = str_v.split(',');
            ip = dict_v[0] + '.' + dict_v[1] + '.' + dict_v[2] + '.' + dict_v[3];
            port = ((int(dict_v[4])) << 8) + int(dict_v[5]);
            return (ip, port);
        else:
            return None;
        
        pass
    
    def SetType(self, flag):
        if(flag):
            command = 'TYPE I\r\n';
        else:
            command = 'type A\r\n';
        
        self.opreateSend(command);
            
    pass


    pass

def processing(cur):
    
#    print cur;
    
    pass

if(__name__ == '__main__'):
    
    fc = ftpclient('192.168.10.148');
    flag = fc.login('zhiwang', '123456');
    
    fc.upload('/home/kelly/xingkong.jpg', '/upload/xk11121.jpg', flag=False, callback=processing);
    
    raw_input('aaa');
    
    pass
